import urllib.request
import json
import base64


def _getkey(obj, keyarr):
    k = keyarr.pop(0)
    if k.isdigit():
        k = int(k)
    if len(keyarr)==0:
        return obj[k]
    else:   
        return _getkey(obj[k], keyarr)

def KEY(keypath):
    return lambda self: _getkey(self.resp, keypath.split("."))

def TYPEWITH(t):
    if type(t)==str:
        return f'\"{t}\"'
    return t

def VAR(key):
    return globals()["wpl_vars"][key]

def initvars():
    globals()["wpl_vars"] = {}


class WebPipelines:
    def __init__(self, baseUrl=""):
        self.baseUrl = baseUrl
        initvars()

    def compile(self, conffilename):
        with open(conffilename, 'r', encoding="utf-8") as conffile:
            conf = json.loads(conffile.read())
        with open(f'{conf["name"]}.py', "w", encoding="utf-8") as scriptfile:
            steps = conf["steps"]
            steparr = [f"WebPipelines({conf['baseUrl']})"]
            for step in steps:
                args = ','.join([f"{k}={TYPEWITH(v)}" for k,v in step["args"].items()])
                steparr.append(f"{step['stype']}({args})")
            scriptfile.write(".".join(steparr))
    
    def baseauth(self, user, password):
        #以下原生的库有问题，废弃使用HTTPBasicAuthHandler
        # password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
        # password_mgr.add_password(None, self.baseUrl,user,password) 
        # self.auth_handler = urllib.request.HTTPBasicAuthHandler(password_mgr) 
        
        #自己做base auth
        up = base64.b64encode(f'{user}:{password}'.encode('utf-8'))
        self.req["headers"].update({"Authorization":f"Basic {up.decode('utf-8')}"})
        return self

    def post(self, url):
        headers = {"accept": "*",'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko',
                                        'Accept-Charset': 'utf-8', 'Content-Type': 'application/json'}
        if hasattr(self, "req") and "headers" in self.req and "Authorization" in self.req["headers"]:
            headers["Authorization"] = self.req["headers"]["Authorization"]
        self.req = {"url":url, "headers":headers, "method":"POST", "params":{}}
        return self
        # print(f"post:{url}")  headers=head, 
    def get(self, url):
        headers = {"accept": "*", 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko'}
        if hasattr(self, "req") and "headers" in self.req and "Authorization" in self.req["headers"]:
            headers["Authorization"] = self.req["headers"]["Authorization"]
        self.req = {"url":url, "headers":headers, "method":"GET", "params":{}}
        return self
    def put(self, url):
        headers = {"accept": "*",'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko',
                                        'Accept-Charset': 'utf-8', 'Content-Type': 'application/json'}
        if hasattr(self, "req") and "headers" in self.req and "Authorization" in self.req["headers"]:
            headers["Authorization"] = self.req["headers"]["Authorization"]
        self.req = {"url":url, "headers":headers, "method":"PUT", "params":{}}
        return self
    def delete(self, url):
        headers = {"accept": "*",'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko',
                                        'Accept-Charset': 'utf-8', 'Content-Type': 'application/json'}
        if hasattr(self, "req") and "headers" in self.req and "Authorization" in self.req["headers"]:
            headers["Authorization"] = self.req["headers"]["Authorization"]
        self.req = {"url":url, "headers":headers, "method":"DELETE", "params":{}}
        return self
    def body(self, bodyjson):
        # url = f"http://{host}:{port}/{name}"
        es_params = json.dumps(bodyjson)
        self.req["data"] = bytes(es_params, 'utf8')
        return self
        # print(f"post:{url}")  headers=head, 
    def head(self, headkv):
        self.req["headers"].update(headkv)
        return self

    def query(self, params):
        self.req["params"].update(params)
        return self

    def jwtToken(self, token):
        # print(token(self))
        self.req["headers"].update({"Authorization":f"Bearer {token(self)}"})
        return self

    def value(self, keyfoo, varname):
        globals()["wpl_vars"][varname] = keyfoo(self)
        return self

    def fetch(self):
        if not (self.req["url"].startswith("http://") or self.req["url"].startswith("https://")):
            self.req["url"] = self.baseUrl+self.req["url"]
        if len(self.req["params"].keys())>0:
            kw=urllib.parse.urlencode(self.req["params"])
            self.req["url"] += "?"+kw
            
        if "params" in self.req.keys():
            self.req.pop("params")

        req = urllib.request.Request(**self.req)
        response = urllib.request.urlopen(req)
        self.resp = json.loads(response.read().decode("utf-8"))
        print(self.req, "->", self.resp)
        return self

    def jsonresult(self, key):
        return self.resp[key]

    def dataframe(self, key):
        import pandas as pd
        lst = [it for it in KEY(key)(self)]
        return pd.DataFrame(lst)

    def data(self, key, name=None):
        import pandas as pd
        lst = [it for it in KEY(key)(self)]
        self.data = pd.DataFrame(lst)
        if name:
            self._dataname = name
        return self
    
    def print(self, value):
        print(value)
        return self
    
    def save(self, filepath):
        import pandas as pd
        if filepath.endswith(".xlsx") or filepath.endswith(".xls"):
            with pd.ExcelWriter(filepath, engine='openpyxl') as writer:
                # df.to_excel(writer, sheet_name='Sheet1')
                if self._dataname:
                    self.data.to_excel(writer, sheet_name=self._dataname, index=False)
                else:
                    self.data.to_excel(writer, index=False)
        elif filepath.endswith(".csv"):
            self.data.to_csv(filepath, encoding='utf-8', index=False)
        return self
    

# WebFetchFlow().auth('http://localhost:81/auth/n_login', 'user01', '123456').fetch()

if __name__=="__main__":
    print(WebPipelines(baseUrl="http://localhost:81").post('/auth/n_login').body({"account":'user01', "password":'123456',"c_type":1}).fetch() \
        .get("/admin/user/page").jwtToken(KEY("data")).fetch().dataframe("data.rows"))
    # print(WebPipelines(baseUrl="http://localhost:81").post("/auth/n_login").body({'account':"user01", 'password':"123456",'c_type':1}).fetch().get("/admin/user/list").jwtToken(KEY('data')).fetch().dataframe('data.rows'))
    # print(WebPipelines(baseUrl="http://localhost:8529").post('/_db/gg/_api/cursor').baseauth("root", "123456") \
    #    .body({"query":"for u in Man return u", "count":'true'}).fetch().dataframe("result"))